package com.apobates.forum.core.security.exposure;

import com.apobates.forum.core.entity.proxy.BoardModeratorReplica;
import com.apobates.forum.core.security.exception.VerificaFailException;
import com.apobates.forum.core.security.exposure.supply.FreezePlugStrategy;
import com.apobates.forum.core.security.exposure.supply.ModeratorPlugStrategy;
import com.apobates.forum.event.elderly.ForumActionEnum;
import com.apobates.forum.member.entity.Member;
import com.apobates.forum.member.entity.MemberRoleEnum;
import com.apobates.forum.utils.lang.TriPredicate;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.Supplier;
import java.util.stream.Stream;

/**
 * 复合检测器的主体
 * 
 * @param <T> 实体
 * @author xiaofanku
 * @since 20200803
 */
public final class ComplexDetectionStrategy<T> {
    private final T entity;
    private final Member operator;
    private final ForumActionEnum action;
    private final Set<MemberRoleEnum> allowRoles;
    
    public ComplexDetectionStrategy(T entity, Member operator, ForumActionEnum action, Set<MemberRoleEnum> allowRoles) {
        this.entity = entity;
        this.operator = operator;
        this.action = action;
        this.allowRoles = allowRoles;
    }
    /**
     * 将T,Member的参数传递到实体配置文件的策略检测中
     * 
     * @param <V> 
     * @param mappingFunction 实体配置文件检测策略中定义的映射函数
     * @return 
     */
    public <V> V config(BiFunction<T, Member, V> mappingFunction){
        return mappingFunction.apply(entity, operator);
    }
    /**
     * 执行扩展检测
     * 
     * @param function 接受三个特定类型的谓词函数
     * @return 
     */
    public ComplexDetectionStrategy<T> plug(TriPredicate<Member, ForumActionEnum, Set<MemberRoleEnum>> function){
        if(function.test(operator, action, allowRoles)){
            return this;
        }
        throw new VerificaFailException("扩展策略检测失败");
    }
    /**
     * 执行版主检测
     * 
     * @param moderators
     * @return 
     */
    public ComplexDetectionStrategy<T> moderatorPlug(Supplier<Stream<BoardModeratorReplica>> moderators){
        if(new ModeratorPlugStrategy(moderators).test(operator, action, allowRoles)){
            return this;
        }
        throw new VerificaFailException("版主扩展策略检测失败");
    }
    /**
     * 执行扩展检测
     * 
     * @param function 接受两个特定类型的谓词函数
     * @return 
     */
    public ComplexDetectionStrategy<T> plug(BiPredicate<Member, ForumActionEnum> function){
        if(function.test(operator, action)){
            return this;
        }
        throw new VerificaFailException("扩展策略检测失败");
    }
    /**
     * 执行新会员冰封检测
     * 
     * @param newMemberFreezeMinute 冰封时长
     * @return 
     */
    public ComplexDetectionStrategy<T> freezePlug(int newMemberFreezeMinute){
        if(new FreezePlugStrategy(newMemberFreezeMinute).test(operator, action)){
            return this;
        }
        throw new VerificaFailException("冰封期扩展策略检测失败");
    }
    /**
     * 获取新会员冰封检测谓词函数
     * 
     * @param newMemberFreezeMinute 冰封时长
     * @param member 当前会员操作者
     * @param action 当前会员进行的操作
     * @return 
     */
    public static FreezePlugStrategy freezeStrategy(int newMemberFreezeMinute, final Member member, final ForumActionEnum action){
        return new FreezePlugStrategy(newMemberFreezeMinute);
    }
}